#include "Xps/Manager/Manager.h"

namespace Xps
{

    Manager::Manager(void)
    {
    }

    Manager::~Manager(void)
    {
    }

    IManager * Manager::getInstance()
    {
        static Manager manager;
        return &manager;
    }

    bool Manager::RegisterProtocol( const std::string &_ProtocolName, IProtocol::Ptr _Protocol )
    {
        ProtocolMapConstIterator iterator = protocol_map.find(_ProtocolName);
        if(iterator != protocol_map.end())
            return false;
        protocol_map.insert(ProtocolMapPair(_ProtocolName,_Protocol));

        for(TaskMapIterator i = task_map.begin(),
            last = task_map.end();
            i!=last; i++)
        {
            ITask::Ptr task = i->second;
            if(task->IsSubscribedToProtocol(_ProtocolName))
            {
                __hook(&IProtocol::OnPacketRecieved,_Protocol.get(),&ITask::Perform,task.get());
            }

        }

        return true;
    }

    bool Manager::UnRegisterProtocol( const std::string &_ProtocolName )
    {
        ProtocolMapIterator iterator = protocol_map.find(_ProtocolName);
        if(iterator == protocol_map.end())
            return false;
        ProtocolMapPair protocol_map_pair = *iterator;
        protocol_map_pair.second->Stop();

        for(TaskMapIterator i = task_map.begin(),
            last = task_map.end();
            i!=last; i++)
        {
            ITask::Ptr task = i->second;
            if(task->IsSubscribedToProtocol(protocol_map_pair.first))
            {
                __unhook(&IProtocol::OnPacketRecieved,protocol_map_pair.second.get(),&ITask::Perform,task.get());
            }

        }

        protocol_map.erase(iterator);
        return true;
    }

    bool Manager::RegisterTask( const std::string &_TaskName, ITask::Ptr _Task )
    {
        TaskMapConstIterator iterator = task_map.find(_TaskName);
        if(iterator != task_map.end())
            return false;
        task_map.insert(TaskMapPair(_TaskName,_Task));

        for(ProtocolMapIterator i = protocol_map.begin(),
            last = protocol_map.end();
            i!=last; i++)
        {
            ProtocolMapPair protocol_map_pair = *i;
            if(_Task->IsSubscribedToProtocol(protocol_map_pair.first))
            {
                __hook(&IProtocol::OnPacketRecieved,protocol_map_pair.second.get(),&ITask::Perform,_Task.get());
            }

        }

        return true;
    }

    bool Manager::UnRegisterTask( const std::string &_TaskName )
    {
        TaskMapIterator iterator = task_map.find(_TaskName);
        if(iterator == task_map.end())
            return false;

        TaskMapPair task_map_pair = *iterator;
        ITask::Ptr task = task_map_pair.second;

        for(ProtocolMapIterator i = protocol_map.begin(),
            last = protocol_map.end();
            i!=last; i++)
        {
            ProtocolMapPair protocol_map_pair = *i;
            if(task->IsSubscribedToProtocol(protocol_map_pair.first))
            {
                __unhook(&IProtocol::OnPacketRecieved,protocol_map_pair.second.get(),&ITask::Perform,task.get());
            }

        }

        task_map.erase(iterator);
        return true;

    }

    bool Manager::PushPacket( const std::string &_ProtocolName, const IPacket::Ptr _Packet )
    {
        ProtocolMapIterator iterator = protocol_map.find(_ProtocolName);
        if(iterator == protocol_map.end())
            return false;
        ProtocolMapPair protocol_map_pair = *iterator;
        protocol_map_pair.second->Send(_Packet);
        return true;
    }

    void Manager::Start()
    {
        for(ProtocolMapIterator i = protocol_map.begin(),
            last = protocol_map.end();
            i!=last; i++)
        {
            IProtocol::Ptr protocol = i->second;
            protocol->Start();
        }
    }

    void Manager::Stop()
    {
        for(ProtocolMapIterator i = protocol_map.begin(),
            last = protocol_map.end();
            i!=last; i++)
        {
            IProtocol::Ptr protocol = i->second;
            protocol->Stop();
        }
    }

    IProtocol::Ptr Manager::getProtocol( const std::string &_ProtocolName )
    {
        ProtocolMapIterator iterator = protocol_map.find(_ProtocolName);
        if(iterator == protocol_map.end())
            return IProtocol::Ptr();
        return iterator->second;
    }

};